package com.clwl.supervise.superviseapp.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONObject;
import com.clwl.supervise.superviseapp.entity.base.SysAppUpdate;
import com.clwl.supervise.superviseapp.entity.base.TsUser;
import com.clwl.supervise.superviseapp.entity.result.ResultCode;
import com.clwl.supervise.superviseapp.entity.result.ResultEntity;
import com.clwl.supervise.superviseapp.mapper.base.SysConfigMapper;
import com.clwl.supervise.superviseapp.service.base.AppUpdateService;
import com.clwl.supervise.superviseapp.util.file.FileUploadUtil;
import com.google.common.collect.Lists;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.http.Method;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

@WebFilter("/*")
@Component
public class UserAuthFilter implements Filter {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisTemplate<String, TsUser> userRedisTemplate;
    @Autowired
    private RedisTemplate<String, String> userStatusTemplate;

    @Autowired
    private AppUpdateService updateService;

    @Value("${app.fileSuffixs}")
    private String fileSuffixs;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        //判断是否是设置的可直接访问的静态文件
        String[] fileSuffixArr = fileSuffixs.split(",");
        ArrayList<String> fileSuffixList = Lists.newArrayList(fileSuffixArr);
        //解决uri中出现多个//无法请求的问题
        String  requestPath = httpServletRequest.getServletPath();
        logger.info("转换前请求地址:{}",requestPath);
        String newUri = requestPath.replace("//","/");
        logger.info("去掉双//后的请求地址:{}",newUri);
        httpServletRequest = new HttpServletRequestWrapper(httpServletRequest){
            @Override
            public String getRequestURI() {
                return newUri;
            }
        };
        logger.info("httpServletRequest:{}",httpServletRequest);
        String lastPath = null;
        try {
            requestPath = httpServletRequest.getServletPath();
            logger.info("转换后请求地址：{}",requestPath);
            lastPath = requestPath.substring(requestPath.lastIndexOf("/") + 1);
            logger.info("获取的最后面的地址：{}",lastPath);
        } catch (Exception e) {
            //如果这段内容出错直接判断用户信息是否正确向下执行。
            logger.error("转换地址信息失败:{}",e.getMessage());
            checkUserInfo(servletRequest, servletResponse, filterChain, httpServletRequest, httpServletResponse);
            return;
        }
        //String uploadBucket =  FileUploadUtil.getMinioBucket();
        String uploadBucket = StringUtils.equals(FileUploadUtil.fileUploadActive, "dev") ? FileUploadUtil.devUploadBucket : StrUtil.blankToDefault(SpringUtil.getBean(SysConfigMapper.class).queryByKey( FileUploadUtil.minioBucketKey).getParamValue(), FileUploadUtil.devUploadBucket);
        logger.info("文件桶名：{}","/"+uploadBucket);
        //判断是否是静态文件，并且是minio的桶开头的地址使用minio解析
//        if(httpServletRequest.getServletPath().startsWith("/"+uploadBucket) && lastPath != null && fileSuffixList.contains(lastPath.substring(lastPath.lastIndexOf(".") + 1))){
        if(httpServletRequest.getServletPath().startsWith("/"+uploadBucket) && lastPath != null ){
            //图片地址转发
            String url = null;
            try {
                logger.info("请求地址:{}",requestPath);
                //使用private桶的时候可以使用下面获取授权地址，能够直接访问。 需要在FileUploadUtil类中的static的代码块中将minioShowClient赋值的注解打开
                url = FileUploadUtil.minioShowClient.getPresignedObjectUrl(
                                GetPresignedObjectUrlArgs.builder()
                                        .method(Method.GET)
                                        .bucket(uploadBucket)
                                        .object(requestPath.replace("/" + uploadBucket+"/",""))
                                        .expiry(1, TimeUnit.DAYS)
                                        .build());
            } catch (Exception e) {
                e.printStackTrace();
            }
            //图片路径重定向，拼接预览minio路径 ， 需要minio 桶权限为public 才可使用此方式。
            //String url = FileUploadUtil.devViewPath + requestPath;
            logger.info("图片重定向地址:{}",url);
            httpServletResponse.sendRedirect(url);
            //filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
//        filterChain.doFilter(servletRequest, servletResponse);
        logger.info("不是静态文件");
        String platform = httpServletRequest.getHeader("platform");
        String version = httpServletRequest.getHeader("version");
        if(StringUtils.isBlank(platform)   && !("/user/login".equals(requestPath) || "/update/checkVersion".equals(requestPath)  || "/sampling/querySamplingStatistics".equals(requestPath)||  "/base/queryPOIByName".equals(requestPath)|| "/update/getNewVersion".equals(requestPath) || "/base/getTianKey".equals(requestPath))){
            //老版本没有这两个参数platform 检测到没有的话提示更新
            ResultEntity resultEntity = ResultEntity.error(ResultCode.APP_UPDATE);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.print(JSONObject.toJSONString(resultEntity));
            return;
        }
        if(StringUtils.isNotBlank(platform) && StringUtils.isNotBlank(version) && !("/user/login".equals(requestPath) || "/update/checkVersion".equals(requestPath)  || "/base/queryPOIByName".equals(requestPath) || "/update/getNewVersion".equals(requestPath)) ) {
            //判断用户的应用版本是否是最新版本  如果是则提示更新
            SysAppUpdate sysAppUpdate = null;
            String sysAppVersion = userStatusTemplate.opsForValue().get("APP_VERSION");
            logger.info("redis中存储的最新APP版本为:{}",sysAppVersion);
            if(StringUtils.isBlank(sysAppVersion)){
                logger.info("redis中没有存储最新APP版");
                sysAppUpdate = updateService.selectTopDateUpdate(platform, null);
                sysAppVersion =  sysAppUpdate.getVersionOne() + "." + sysAppUpdate.getVersionTwo() + "." + sysAppUpdate.getVersionThree();
                userStatusTemplate.opsForValue().set("APP_VERSION",sysAppVersion);
            }

            boolean updateStatus =  isUpdateNeeded(sysAppVersion,version);
            if (updateStatus) {
                ResultEntity resultEntity = ResultEntity.error(ResultCode.APP_UPDATE);
                PrintWriter writer = httpServletResponse.getWriter();
                writer.print(JSONObject.toJSONString(resultEntity));
                return;
            }
        }
        if ("/user/login".equals(requestPath) || "/update/checkVersion".equals(requestPath)  || "/update/getNewVersion".equals(requestPath)
                || "/test/documentHelp".equals(requestPath) || "/base/uploadCheckTest".equals(requestPath) ||  "/base/queryPOIByName".equals(requestPath) || "/sampling/querySamplingStatistics".equals(requestPath) || "/favicon.ico".equals(requestPath) || "/base/getTianKey".equals(requestPath)) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            checkUserInfo(servletRequest, servletResponse, filterChain, httpServletRequest, httpServletResponse);
        }
    }

    private void checkUserInfo(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {
        String token = httpServletRequest.getHeader("token");
        logger.info("token:{}",token);
        if(token == null){
            ResultEntity resultEntity =  ResultEntity.error(ResultCode.AUTH_ERROR);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.print(JSONObject.toJSONString(resultEntity));
            return;
        }
        TsUser user = userRedisTemplate.opsForValue().get(token);
        if (user == null) {
            ResultEntity resultEntity =  ResultEntity.error(ResultCode.AUTH_ERROR);
            PrintWriter writer = httpServletResponse.getWriter();
            writer.print(JSONObject.toJSONString(resultEntity));
        } else {
            Object userStatus = userStatusTemplate.opsForHash().get("user_disabled_status", user.getId().toString());
            if (StringUtils.equals(userStatus+"","1") ) {
                ResultEntity resultEntity =  ResultEntity.error(ResultCode.DISABLED_ERROR);
                PrintWriter writer = httpServletResponse.getWriter();
                writer.print(JSONObject.toJSONString(resultEntity));
                return;
            }
            //延长用户过期时间
             userRedisTemplate.expire(token, 12, TimeUnit.DAYS);
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    /**
     * 判断是否存在新版本
     * @param sysVersion 系统版本
     * @param currentVersion 客户版本
     * @return
     */
    public boolean isUpdateNeeded(String sysVersion, String currentVersion) {
        String[] sysVersions = sysVersion.split("\\.");
        String[] currentVersions = currentVersion.split("\\.");

        for (int i = 0; i < sysVersions.length; i++) {
            int sysPart = Integer.parseInt(sysVersions[i]);
            int currentPart = Integer.parseInt(currentVersions[i]);

            if (sysPart > currentPart) {
                return true;
            } else if (sysPart < currentPart) {
                return false;
            }
        }

        // 如果所有部分都相等，则不需要更新
        return false;
    }
}
